#pragma once

#ifndef __CANVAS_REGEX_REGEX_H
#define __CANVAS_REGEX_REGEX_H

#include "..\ObjectString.h"
#include "..\Ptr.h"
#include "..\Collection.h"

namespace Canvas
{
	namespace RegExInternal
	{
		class PureResult;
		class PureInterpretor;
		class RichResult;
		class RichInterpretor;
	}

	namespace RegEx
	{
		using namespace Collection;
		class RegExString
		{
		protected:
			WString value;
			int start;
			int length;
		public:
			RegExString(int start = 0);
			RegExString(const WString& _string, int _start, int _length);

			int Start() const;
			int Length() const;
			const WString& Value() const;
			bool operator==(const RegExString& string) const;
		};

		class RegExMatch
		{
			friend class RegEx;
		public:
			typedef Ptr<RegExMatch>	Ref;
			typedef Collection::List<Ref> List;
			typedef Collection::List<RegExString> CaptureList;
			typedef Collection::Group<WString, RegExString> CaptureGroup;

		protected:
			CaptureList captures;
			CaptureGroup groups;
			bool success;
			RegExString	result;

			RegExMatch(const WString& _string, RegExInternal::PureResult* _result);
			RegExMatch(const WString& _string, RegExInternal::RichResult* _result, RegExInternal::RichInterpretor* interpreter);
			RegExMatch(const RegExString& result);

		public:
			bool Success() const;
			const RegExString& Result() const;
			const CaptureList& Captures() const;
			const CaptureGroup& Groups() const;
		};

		class RegEx : public Object, public NonCopyable
		{
		protected:
			RegExInternal::PureInterpretor* pure;
			RegExInternal::RichInterpretor* rich;
			void Process(const WString& text, 
				bool keepEmpty, 
				bool keepSuccess, 
				bool keepFail, 
				RegExMatch::List& matches) const;
		public:
			RegEx(const WString& code, bool preferPure = true);

			bool IsPureMatch() const;
			bool IsPureTest() const;

			RegExMatch::Ref MatchHead(const WString& text) const;
			RegExMatch::Ref Match(const WString& text) const;
			bool TestHead(const WString& text) const;
			bool Test(const WString& text) const;
			void Search(const WString& text, RegExMatch::List& matches) const;
			void Split(const WString& text, bool keepEmptyMatch, RegExMatch::List& matches) const;
			void Cut(const WString& text, bool keepEmptyMatch, RegExMatch::List& matches) const;

		};

		class RegExToken
		{
		public:
			int start;
			int length;
			int tokne;
			const wchar_t* reading;
			int codeIndex;
			bool completeToken;

			int rowStart;
			int columnStart;
			int rowEnd;
			int columnEnd;
			
			bool operator==(const RegExToken& token) const;
			bool operator==(const wchar_t* _token) const;
		};

		class RegExTokens : public Object, public IEnumerable<RegExToken>
		{
			friend class RegExLexer;
		protected:
			RegExInternal::PureInterpretor* pure;
			const Array<int>& stateTokens;
			WString code;
			int codeIndex;

			RegExTokens(RegExInternal::PureInterpretor* _pure, const Array<int>& _stateTokens, const WString& _code, int _codeIndex);
		public:
			RegExTokens(const RegExTokens& tokens);

			IEnumerator<RegExToken>* CreateEnumerator() const;
			void ReadToEnd(List<RegExToken>& tokens, bool(*discard)(int) = nullptr) const;
		};

		class RegExLexerWalker : public Object
		{
			friend class RegExLexer;
		protected:
			RegExInternal::PureInterpretor* pure;
			Array<int>& stateTokens;
			RegExLexerWalker(RegExInternal::PureInterpretor* _pure, const Array<int>& _stateTokens);
		public:
			RegExLexerWalker(const RegExLexerWalker& walker);
			~RegExLexerWalker();
			int GetStartState() const;
			int GetRelatedToken(int state) const;
			void Walk(wchar_t input, int& state, int& token, bool& finalState, bool& previousTokenStop) const;
			int Walk(wchar_t input, int state) const;
			bool IsClosedToken(const wchar_t* input, int length) const;
			bool IsClosedToken(const WString& input) const;
		};

		class RegExLexerColorizer : public Object
		{
			friend class RegExLexer;
		public:
			typedef void(*TokenProc)(void* argument, int start, int length, int token);
		protected:
			RegExLexerWalker walker;
			int currentState;
			RegExLexerColorizer(const RegExLexerWalker& _walker);
		public:
			RegExLexerColorizer(const RegExLexerColorizer& colorizer);
			~RegExLexerColorizer();

			void Reset(int state);
			void Pass(wchar_t input);
			int GetStartState() const;
			int GetCurrentState() const;
			void Colorize(const wchar_t* input, int length, TokenProc tokenProc, void* tokenProcArgument);
		};

		class RegExLexer : public Object, public NonCopyable
		{
		protected:
			RegExInternal::PureInterpretor* pure;
			Array<int> ids;
			Array<int> stateTokens;
		public:
			RegExLexer(const IEnumerable<WString>& tokens);
			~RegExLexer();

			RegExTokens Parse(const WString& code, int codeIndex = -1) const;
			RegExLexerWalker Walk() const;
			RegExLexerColorizer Colorize() const;
		};
	}
}

#endif // __CANVAS_REGEX_REGEX_H